/**
 * 
 */
package com.puneet.graphqueries;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import partitioner.PartitionDAO;
import util.ArrayUtil;

import com.puneet.graphqueries.MessageHandlerAction.Response;
import com.puneet.graphqueries.yamlconfig.Configuration;

/**
 * @author puneet
 * 
 */
public class KHopMessageHandler implements PartitionMessageHandler {
	private int k;
	private PartitionDAO partitionDAO;
	private static Pattern nodeQueryMessagePattern = Pattern
			.compile("^node:\\s*(.+?)\\sk:\\s*(\\d+)$");
	// This is to avoid cycles
	private static Set<String> alreadyHandledNodes = new HashSet<String>();
	private boolean running;

	public KHopMessageHandler(int k, PartitionDAO partitionDAO) {
		System.out.println("K value:" + k);
		this.k = k;
		this.partitionDAO = partitionDAO;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.puneet.graphqueries.PartitionMessageHandler#handleMessage(java.lang
	 * .String)
	 */
	@Override
	public MessageHandlerAction handleMessage(String msg, Configuration config,boolean start) {
		System.out.println("Handling:" + msg);
		MessageHandlerAction action = new MessageHandlerAction();
		Matcher nodeQueryPatternMatcher = nodeQueryMessagePattern.matcher(msg);

		// Message Types
		// Exit
		if (msg.startsWith("exit")) {
			action.setTakeAction(Response.EXIT);
		} else if (nodeQueryPatternMatcher.matches()) {

			running = true;
			String node = nodeQueryPatternMatcher.group(1);
			int nodek = Integer.parseInt(nodeQueryPatternMatcher.group(2));
			System.out.println("Handling: " + node + " with kval:" + nodek);
			KHopNodeNotFoundHandler nodeNotFoundHandler = new KHopNodeNotFoundHandlerImpl(
					config);

			handleNode(node, nodek, config, nodeNotFoundHandler,!start);
			action.setTakeAction(Response.CONTINUE);
		} else {
			System.err.println("Unrecognized message:" + msg);
		}
		running = false;
		return action;
	}

	private void handleNode(String node, int nodek, Configuration config,
			KHopNodeNotFoundHandler nodeNotFoundHandler,boolean initCall) {
		if (alreadyHandledNodes.add(node)) {
			System.out.println("Handling node:" + node + " with k:" + nodek);
			if (nodek >= k) {
				return;
			}

			if (partitionDAO.containsNode(node)) {
				System.out.println("Found node:" + node + " here");
				try {
					List<String> neighbors = partitionDAO.getNeighbors(node);
					BufferedWriter bw = new BufferedWriter(new FileWriter(
							config.getOpconfig().getFile(), true));
					bw.write(ArrayUtil.join(neighbors, " ") + " k: "
							+ (nodek + 1) + "\n");
					bw.close();
					for (String neighbor : neighbors) {
						handleNode(neighbor, nodek + 1, config,
								nodeNotFoundHandler,false);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				System.out.println("COuldnt find node:" + node + " here");
				
				nodeNotFoundHandler.handleNodeNotFound(node, nodek);

			}
		}
	}

	@Override
	public boolean done() {
		return !running;
	}

}
